/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.jmmarca.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 *
 * @author SmartBr
 */
public class UtilClass {

    private static final Map<Class, Class> classes;

    static {
        classes = new HashMap<Class, Class>();
        classes.put(boolean.class, Boolean.class);
        classes.put(char.class, Character.class);
        classes.put(byte.class, Byte.class);
        classes.put(short.class, Short.class);
        classes.put(long.class, Long.class);
        classes.put(float.class, Float.class);
        classes.put(int.class, Integer.class);
        classes.put(double.class, Double.class);
        classes.put(void.class, Void.class);
    }

    public static void invokeSet(Object obj, Object value, String... methods) {
        Object ret = null;
        if (methods != null) {
            for (int i = 0; i < methods.length; i++) {
                if (i == methods.length - 1) {
                    UtilClass.setAtributo(ret, methods[i], value);
                } else {
                    ret = UtilClass.getAtributo(obj, methods[i]);
                }
            }
        }
    }

    public static void setAtributo(Object obj, String nomeMetodo, Class<?> tipoParametro, Object... parametros) {
        Class classe = obj.getClass();
        try {
            Method metodo = classe.getMethod("set" + UtilString.firstUpper(nomeMetodo), tipoParametro);
            metodo.invoke(obj, parametros);
        } catch (Exception ex) {
            System.out.println("Erro ao chamar o metodo " + nomeMetodo + "\n " + ex);
        }
    }

    public static void setAtributo(Object obj, String nomeMetodo, Object... parametros) {
        Class classe = obj.getClass();
        try {
            Method[] metodos = classe.getMethods();
            for (Method metodo : metodos) {
                if (metodo.getName().equals("set" + UtilString.firstUpper(nomeMetodo))) {
                    Method method = null;
                    try {
                        method = classe.getMethod("get" + UtilString.firstUpper(nomeMetodo));
                    } catch (Exception e) {
                        method = classe.getMethod("is" + UtilString.firstUpper(nomeMetodo));
                    }
                    try {
                        if (method.getReturnType().isEnum()) {
                            try {
                                Object[] objs = new Object[parametros.length];

                                for (int i = 0; i < parametros.length; i++) {
                                    if (parametros[i] instanceof String) {
                                        Class returnType = method.getReturnType();
                                        objs[i] = Enum.valueOf(returnType, (String) parametros[i]);
                                    } else {
                                        objs[i] = parametros[i];
                                    }
                                }
                                metodo.invoke(obj, objs);
                            } catch (Exception e) {
                                metodo.invoke(obj, parametros);
                            }
                        } else {
                            metodo.invoke(obj, parametros);
                        }
                    } catch (Exception e) {
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static Object getAtributo(Object obj, String fieldName) {
        // Ex.: produto.codigo
        if (fieldName.contains(".")) {
            Object ret = getAtributo(obj, fieldName.split("[.]")[0]);
            return getAtributo(ret, fieldName.split("[.]")[1]);
        }
        Class classe = obj.getClass();
        Object retorno = null;
        try {
            Method metodo = classe.getMethod("get" + UtilString.firstUpper(fieldName));
            retorno = metodo.invoke(obj);
        } catch (Exception ex) {
            try {
                Method metodo = classe.getMethod("is" + UtilString.firstUpper(fieldName));
                retorno = metodo.invoke(obj);
            } catch (Exception e) {
            }
        }
        return retorno;
    }

    public static Method getMethod(Class aClass, String method) {
        Method[] methods = aClass.getMethods();

        for (Method m : methods) {
            if (m.getName().equalsIgnoreCase(method)) {
                return m;
            }
        }
        return null;
    }

    public static <T> T cast(Class<T> aClass, Object valor) {
        try {
            if (valor != null) {
                if (!aClass.isPrimitive()) {
                    if (valor instanceof Enum) {
                        return (T) valor;
                    } else if (valor instanceof String) {
                        Constructor constructor = aClass.getConstructor(String.class);
                        return (T) constructor.newInstance(valor);
                    } else {
                        return (T) valor;
                    }
                } else if (classes.containsKey(aClass) && valor instanceof String) {
                    aClass = classes.get(aClass);
                    Constructor constructor = aClass.getConstructor(String.class);
                    return (T) constructor.newInstance(valor);
                } else {
                    return (T) valor;
                }
            }
        } catch (Exception ex) {
            System.out.println("Erro class " + aClass.getName() + " - " + valor);
        }
        return null;
    }

    public static Set<Field> getAllFields(Class clz) {
        Set<Field> fields = new HashSet<Field>();
        try {
            fields.addAll(Arrays.asList(clz.getSuperclass().getDeclaredFields()));
            fields.addAll(Arrays.asList(clz.getSuperclass().getFields()));
            fields.addAll(Arrays.asList(clz.getDeclaredFields()));
            fields.addAll(Arrays.asList(clz.getFields()));
        } catch (Exception e) {
        }
        return fields;
    }

    public static Class getFieldType(Class clz, String field) {
        try {
            Set<Field> allFields = getAllFields(clz);
            for (Field f : allFields) {
                if (f.getName().equalsIgnoreCase(field)) {
                    return f.getType();
                }
            }
        } catch (Exception e) {
        }
        return null;
    }

    public static Class getTypeList(Class clz, String fieldList) {
        try {
            Field field = null;
            try {
                field = clz.getDeclaredField(fieldList);
            } catch (Exception e) {
                field = clz.getSuperclass().getDeclaredField(fieldList);
            }
            ParameterizedType stringListType = (ParameterizedType) field.getGenericType();
            Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
            return stringListClass;
        } catch (Exception e) {
        }
        return null;
    }

    public static Object invokeGet(Object obj, String field) {
        try {
            Class clz = obj.getClass();
            String[] fields = field.split("[.]");
            String name;
            for (String f : fields) {
                if (obj != null) {
                    try {
                        name = "get".concat(UtilsString.capitalize(f));
                        obj = clz.getMethod(name).invoke(obj);
                    } catch (NoSuchMethodException n) {
                        name = "is".concat(UtilsString.capitalize(f));
                        obj = clz.getMethod(name).invoke(obj);
                    }
                }
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Field getField(Class clzz, String field) {
        Field f = null;
        try {
            try {
                f = clzz.getField(field);
                if (f != null) {
                    return f;
                }
            } catch (Exception e) {
            }
            try {
                f = clzz.getDeclaredField(field);
                if (f != null) {
                    return f;
                }
            } catch (Exception e) {
            }
            try {
                f = clzz.getSuperclass().getField(field);
                if (f != null) {
                    return f;
                }
            } catch (Exception e) {
            }
            try {
                f = clzz.getSuperclass().getDeclaredField(field);
                if (f != null) {
                    return f;
                }
            } catch (Exception e) {
            }
        } catch (Exception e) {
        }
        return f;
    }

    public static boolean fieldExists(Class clzz, String field) {
        try {
            try {
                if (clzz.getField(field) != null) {
                    return true;
                }
            } catch (Exception e) {
            }
            try {
                if (clzz.getDeclaredField(field) != null) {
                    return true;
                }
            } catch (Exception e) {
            }
            try {
                if (clzz.getSuperclass().getField(field) != null) {
                    return true;
                }
            } catch (Exception e) {
            }
            try {
                if (clzz.getSuperclass().getDeclaredField(field) != null) {
                    return true;
                }
            } catch (Exception e) {
            }
        } catch (Exception e) {
        }
        return false;
    }

    private boolean isEmpty(Collection collection) {
        if (collection != null) {
            if (collection.isEmpty()) {
                return true;
            }
        }
        return false;
    }
}
